// ###############   to implement a utility matrix class using vectors from STL

/**
  * @file Matrix.h  
  * @author Juber Patel
  * 
  * Utility vector and matrix classes

 */

 
#ifndef MATRIX_H
#define MATRIX_H 

#include <iostream>
#include <vector>
#include <fstream>
#include <cmath>


using namespace std;


class Vector : public vector<double>
{
    
    
public:

    static const double TOLERANCE=0.000001;
	
    Vector(){}
	Vector(const Vector& another);
	
	/**
	  * @brief Create a new vector
	  * @param Elements number of elements in the vector
	  * @param Val initial value for all elements
	  * @return this Vector
	 */
    Vector(long elements,double val=0);
	~Vector();
	
	Vector& operator=(const Vector& another);
	bool operator<(const Vector& another) const;
	bool operator==(const Vector& another) const;
	
	//canceled for the time being
	//reference operator[](unsigned int j) const { const vector<double> * p=this; return p->operator[](j-1);  }
	
	/**
	  * @brief decide if two nubers are nearly equal using TOLERENCE value
	  * @param num1 first number
	  * @param num2 second number
	  * @return true if abs(num1-num2) < TOLERENCE otherwise false
	  *
	 */
	static bool nearlyEqual(double num1,double num2);
	bool nearlyEqualTo(const Vector& another) const;
	bool isDominant(long col) const;
	double largestCoord() const;
	void disp() const;
};



class Matrix : public vector<Vector>
{
    

public:

    
	enum DIR{RM=1,CM};
	static const double TOLERANCE=0.000001;
	
    Matrix(){}
	Matrix(const Matrix& source);
    Matrix(long rows,long coloumns,double val=0);
	Matrix(const char * fileName);    //string argument does not work
	Matrix(const Vector& v,DIR dir=RM);
	~Matrix();
	
	
	bool Matrix::nearlyEqualTo(const Matrix& another) const;
	
	Matrix& operator=(const Matrix& another);
		
	bool operator==(const Matrix& another) const;
	
	//canceled for the time being. i was trying to make it start with [1][1] instead of [0][0]
	//reference operator[](unsigned int i) const { const vector<Vector> * p=this; return p->operator[](i-1); }
	
	bool save(const char * fileName) const;
	
	//number of rows
	long numRows() const {return this->size();}
	
	//number of rows
	
	// number of coloumns 
	long numCols() const {return (*this)[0].size();}
	
	//use [][] to access element at given position (starts with (0,0))
	
	
	//read matrix from file
	
	//write matrix to file 
	
	//display a row
	void dispRow(long rownum) const;
	
	//display the entire matrix
	void disp() const;
	
	//add 2 matrices
	Matrix operator+(const Matrix& b) const;
	
	// add scalar to matrix
	//Matrix operator+(double b) const;
	
	//substract matrices
	Matrix operator-(const Matrix& b) const;
	
	//transepose of a matrix
	Matrix transepose() const;
	
	//multiply 2 matrices
	Matrix operator* (const Matrix& b) const;
	
	//multiply the matrix by a scalar
	Matrix& operator*(double scalar);
	
	//multily a row by a scalar
	Matrix& multRow(long rowNumber,double scalar);
	
	// divide row by a scalar
	Matrix& divRow(long rowNumber,double scalar);
	
	//swap rows
	Matrix& swapRows(long first,long second);
	
	//add a scalar multiple of a row to another row
	Matrix& addMult(long first,double multiple,long second);
	
	// is the matrix symmetric
	bool isSymmetric() const;
	
	//concatenate two matrices having equal rows
	Matrix concat(const Matrix& b) const;
	
	
	bool hasGoodPivotIn(long rowNumber) const;
	
	// return true if that column contains zero
	bool isColZero(long colNumber);
	
	
};



class SquareMatrix : public Matrix
{
    
protected:

    Matrix * Eigenvalues;
    long eigenvalueCounter;
    
public:

	SquareMatrix():Matrix(){ Eigenvalues = new Matrix(numRows(),1); eigenvalueCounter=0;}
    SquareMatrix(const char * fileName);
    SquareMatrix(long rows,long val=0):Matrix(rows,rows,val)
    	{Eigenvalues = new Matrix(numRows(),1);eigenvalueCounter=0;}
    SquareMatrix(const Matrix& another):Matrix(another)
    	{Eigenvalues = new Matrix(numRows(),1);eigenvalueCounter=0;}

    //required for Gauss and Jacobi iterative methods
	bool makeDiagonallyDominant(Matrix& B);
	bool isDiagonal() const;
	
	
		
	bool isSingular() const {}    
	bool isInvertible() const {}
	SquareMatrix inverse() const {}
    double determinant() const {}
    

private:

	//find and swap with a row such that diagonal element in 'row' becomes greatest in magnitude
	//return true if successful otherwise false
    bool findDominantFor(long row, Matrix& B);	
	

};


#endif      //end of MATRIX_H
